import json
import sys
import os
from datetime import datetime
import json
import hashlib
import shutil
from collections import defaultdict
from robot.api import ExecutionResult, ResultVisitor

ALLURE_LOG_PATH = "/home/ubuntu/workspace/logs/Space"
VERSION_RECORD_PATH = "/home/ubuntu/workspace/space/Execution/DailyJobVersionRecord.json"

###class CopyHistory is copied from file copyAllureHistory.py
class CopyHistory(object):
    def getLastVersion(self,json_path,upgrade,old_java_version=None):
        file_size = os.path.getsize(json_path)
        # Check if the file is empty
        if file_size == 3:
            return None
        else:   
            with open(json_path,'r') as file:
                content_json=json.loads(file.read())
            if upgrade == "TRUE":
                #Change last version with old JRE version
                with open(json_path,'w') as file:
                    content_json[0]["version"]=content_json[0]["version"]+"_"+old_java_version
                    content=json.dumps(content_json,indent=1)
                    file.write(content)
            return  content_json[0]["version"]

    def copyHistory(self,last_version,current_version):
        path_string = "{}/Allure_Report_{}/history {}/{}/allure_log".format(ALLURE_LOG_PATH,last_version,ALLURE_LOG_PATH,current_version)
        os.system('cp -r '+path_string)

    def updateDailyJobVersion(self,json_path,current_version):
        current_time=datetime.now().strftime("%Y-%m-%d")
        with open(json_path,'r') as file:
            if os.path.getsize(json_path)==3:
                content_json = [{'version':current_version,"date":current_time}]
            else:   
                content_json=json.loads(file.read())
                content_json.insert(0,{'version':current_version,"date":current_time})
        with open(json_path,'w') as file:
            content=json.dumps(content_json,indent=1)
            file.write(content)
        return

    def runBeforeGenerateReport(self,json_path,current_version,upgrade,old_java_version=None):
        last_version=self.getLastVersion(json_path,upgrade=upgrade,old_java_version=old_java_version)
        if last_version!=None:
           self.copyHistory(last_version,current_version)
           self.updateDailyJobVersion(json_path,current_version)

##############################      
#below two classes is used for add defect cases in allure report
class HandlerAllure():
    def getCaseContent(self,casename,casesFile):
        casesContent = dict()
        cases = json.load(open(casesFile,encoding = 'UTF-8'))
        cases = cases['children'][0]['children']
        for n in range(len(cases)):
            moduleCases = cases[n]
            moduleCases = moduleCases['children']
            for m in range(len(moduleCases)):
                childrenCases = moduleCases[m]['children']
                if childrenCases[0]['name'] == casename:
                    casesContent.update([('name',childrenCases[0]['name']),
                    ('uid',childrenCases[0]['uid']),
                    ('parentUid',childrenCases[0]['parentUid']),
                    ('status',childrenCases[0]['status']),
                    ('flaky',childrenCases[0]['flaky']),
                    ('newFailed',childrenCases[0]['newFailed']),
                    ('newPassed',childrenCases[0]['newPassed']),
                    ('newBroken',childrenCases[0]['newBroken']),
                    ('retriesCount',childrenCases[0]['retriesCount']),
                    ('retriesStatusChange',childrenCases[0]['retriesStatusChange']),
                    ('parameters',childrenCases[0]['parameters'])
                    ])
                    casesContent['time'] =dict()
                    casesContent['time'].update([('start',childrenCases[0]['time']['start']),
                    ('stop',childrenCases[0]['time']['stop']),
                    ('duration',childrenCases[0]['time']['duration'])
                    ])
                    break
        return casesContent        

    def addCasesToFile(self,casesAll,categoriesFile,casesFile,index,casetype):
        # order fatal=1, task=2, defect=3
        m = hashlib.new('md5')
        m.update(b'Cases link Defects')
        uid1=m.hexdigest()
        m.update(b'Cases link Tasks')
        uid2=m.hexdigest()
        categories = json.load(open(categoriesFile,encoding = 'UTF-8'))
        categories['children'].append(dict())
        if  len(categories['children'])>index: 
            if casetype == 0 :
                if  categories['children'][index].hasOwnProperty('Cases with Defect'):
                    categories['children'][index].update([('name','Cases with Defect'),('uid',uid1)])
            else: 
                if  categories['children'][index].hasOwnProperty('Cases with Task'):
                    categories['children'][index].update([('name','Cases with Task'),('uid',uid2)])
            categories['children'][index]['children']=[]
  
        count = 0
        for keys in casesAll:
            m.update(keys.encode('utf-8'))
            uidtemp = m.hexdigest()
            if  len(categories['children'])>index: 
                categories['children'][index]['children'].append(dict())
                categories['children'][index]['children'][count].update([
                ('name',keys),  
                ('uid',uidtemp),
                ('children',[])
                ])
                for k in range(len(casesAll[keys])):
                    tempCasesContent = self.getCaseContent(casesAll[keys][k],casesFile)
                    if len(tempCasesContent) != 0:
                        categories['children'][index]['children'][count]['children'].append(tempCasesContent)  
                    else:
                        print('cannot locate case: '+ casesAll[keys][k])   
                count += 1
                 
        with open(categoriesFile, 'w', encoding='utf-8') as fw:
            fw.write(json.dumps(categories, ensure_ascii=False))
            fw.close

    def updateBrokenCase(self,caseToUpdate,caseFileToUpdate):
        caseAll = json.load(open(caseFileToUpdate,encoding = 'UTF-8'))
        cases = caseAll['children']
    
        for m in range(len(cases)):    
            if 'newBroken' in cases[m]:
                for index in range(len(caseToUpdate)):
                    if cases[m]['name'] == caseToUpdate[index]:
                        # print(caseToUpdate[index])
                        caseAll['children'][m]['newBroken']=True           
            else:
                moduleCases = cases[m]['children']   
                for n in range(len(moduleCases)):
                    if 'newBroken' in moduleCases[n]:
                        for index in range(len(caseToUpdate)):
                            if moduleCases[n]['name'] == caseToUpdate[index]:  
                                # print(caseToUpdate[index])
                                caseAll['children'][m]['children'][n]['newBroken']=True       
                    else:
                        subCases = moduleCases[n]  
                        for k in range(len(subCases['children'])):
                            for index in range(len(caseToUpdate)):
                                if subCases['children'][k]['name'] ==  caseToUpdate[index]:  
                                    # print(caseToUpdate[index])     
                                    caseAll['children'][m]['children'][n]['children'][k]['newBroken']=True             
        with open(caseFileToUpdate, 'w', encoding='utf-8') as fw:
            fw.write(json.dumps(caseAll, ensure_ascii=False))
            fw.close      

class Visitor(ResultVisitor):
    def __init__(self):
        self.collectTaskCases = defaultdict(list)
        self.collectDefectCases = defaultdict(list)
        self.collectDocCases = []

    def end_test(self, test):
        if test.doc != "" :   
            lowDoc = test.doc.lower()
            if lowDoc.find("task") != -1 or lowDoc.find("defect") != -1:
                self.collectDocCases.append(test.name)
        if test.doc != "" and test.status == "FAIL":   
            lowDoc = test.doc.lower()
            splitDoc = lowDoc.split(';')
            for i in range(len(splitDoc)):
                tempDocs = splitDoc[i].split(':')
                if tempDocs[0].find("task") != -1:
                    self.collectTaskCases[tempDocs[0].strip()].append(test.name)
                if tempDocs[0].find("defect") != -1:
                    self.collectDefectCases[tempDocs[0].strip()].append(test.name)     

###########################
# this class is copyied from file addVersionInAllureJson.py
###########################
class AddVersionInAllureJson(object):
    def getVersions(self,version_json):
        versions=[]
        with open(version_json,'r') as file:
            content_json=json.loads(file.read())
        for version_info in content_json:
            versions.append(version_info["version"])
        return versions

    def addVersionInHistoryTrend(self,version_json,historytrend_path):
        versions = self.getVersions(version_json)
        with open(historytrend_path,'r') as file:
            histroy_trend_json=json.loads(file.read())
        try:
            for i in range(len(histroy_trend_json)):
                histroy_trend_json[i]["buildOrder"]=versions[i]
        except Exception as error:
            print(error)
        histroy_trend_content=json.dumps(histroy_trend_json,indent=1)
        with open(historytrend_path,'w') as file:
            file.write(histroy_trend_content)

    def runAfterGenerateReport(self,version_json,historytrend_path,retrytrend_path,durationtrend_path,categoriestrend_path):
        self.addVersionInHistoryTrend(version_json,historytrend_path)
        self.addVersionInHistoryTrend(version_json,retrytrend_path)
        self.addVersionInHistoryTrend(version_json,durationtrend_path)
        self.addVersionInHistoryTrend(version_json,categoriestrend_path)    


####copy allure history
def copy_history(current_version):
    CopyHistory().runBeforeGenerateReport(VERSION_RECORD_PATH,current_version,"False",None)
        
##add defect in 
def add_defect_cases(current_version):
    casesFile= ALLURE_LOG_PATH+"/allure_report_"+current_version+"/data/suites.json"
    categoriesFile=ALLURE_LOG_PATH+"/allure_report_"+current_version+"/data/categories.json"
    readFromOutputFile=ALLURE_LOG_PATH+"/"+current_version+"/Regression/output.xml"
    behaviorsFile=ALLURE_LOG_PATH+"/allure_report_"+current_version+"/data/behaviors.json"
    originFile = ALLURE_LOG_PATH+"/allure_report_"+current_version+"/data/categories_save.json"

    visitor = Visitor()
    allureHandler = HandlerAllure()
    result = ExecutionResult(readFromOutputFile)
    result.visit(visitor)
    
    # order fatal=1, task=2, defect=3
    indexTask = 2
    if len(visitor.collectTaskCases) == 0:
        allureHandler.addCasesToFile(visitor.collectDefectCases,categoriesFile,casesFile,indexTask,0)
    else:    
        allureHandler.addCasesToFile(visitor.collectTaskCases,categoriesFile,casesFile,indexTask,1)
        if len(visitor.collectDefectCases) != 0:
            allureHandler.addCasesToFile(visitor.collectDefectCases,categoriesFile,casesFile,indexTask+1,0)
    print("Finish update catogories")
    allureHandler.updateBrokenCase(visitor.collectDocCases,behaviorsFile) 
    print("Finish update broken case")         


def add_allure_in_history(current_version):
    historytrend_path=ALLURE_LOG_PATH+"/Allure_Report_"+current_version+"/widgets/history-trend.json"
    retrytrend_path=ALLURE_LOG_PATH+"/Allure_Report_"+current_version+"/widgets/retry-trend.json"
    durationtrend_path=ALLURE_LOG_PATH+"/Allure_Report_"+current_version+"/widgets/duration-trend.json"
    categoriestrend_path=ALLURE_LOG_PATH+"/Allure_Report_"+current_version+"/widgets/categories-trend.json"
    AddVersionInAllureJson().runAfterGenerateReport(VERSION_RECORD_PATH,historytrend_path,retrytrend_path,durationtrend_path,categoriestrend_path)
